"""Session management routes."""
import uuid
from datetime import datetime
from flask import request, current_app
from flask_restx import Namespace, Resource, fields
from flask_jwt_extended import jwt_required, get_jwt_identity
from app.models.location import Location
from app.models.route import Route
from app.models.walking_session import WalkingSession
from app.utils.error_handler import ErrorResponse
from app.routes.mock_data import MOCK_SESSION_HISTORY

api = Namespace('session', description='Walking session operations')

# In-memory session storage for development
_mock_sessions = {}

# Models
start_session_model = api.model('StartSession', {
    'target_poi_id': fields.String(required=True),
    'route_id': fields.String(required=True)
})

update_location_model = api.model('UpdateLocation', {
    'latitude': fields.Float(required=True),
    'longitude': fields.Float(required=True),
    'accuracy': fields.Float(required=True)
})


@api.route('/start')
class StartSession(Resource):
    """Start session endpoint."""
    
    @api.expect(start_session_model)
    def post(self):
        """Start a new walking session.
        
        Validates: Requirements 1.5
        """
        data = request.get_json()
        
        # Get parameters
        target_poi_id = data.get('target_poi_id') or data.get('poi_id')
        route_data = data.get('route')
        
        if not target_poi_id:
            api.abort(400, 'target_poi_id or poi_id is required')
        
        # Create mock session for development
        session_id = str(uuid.uuid4())
        now = datetime.now()
        
        mock_session = {
            'id': session_id,
            'user_id': 'dev_user',
            'route_id': route_data.get('id') if route_data else str(uuid.uuid4()),
            'status': 'active',
            'start_time': now.isoformat(),
            'current_location': route_data.get('start_location') if route_data else None,
            'visited_poi_ids': [],
            'total_distance': 0,
            'target_poi_id': target_poi_id,
            'route': route_data
        }
        
        _mock_sessions[session_id] = mock_session
        
        return {
            'success': True,
            'session_id': session_id,
            'session': mock_session,
            'is_mock': True
        }, 201


@api.route('/<string:session_id>/location')
class UpdateSessionLocation(Resource):
    """Update session location endpoint."""
    
    @api.expect(update_location_model)
    def put(self, session_id):
        """Update session location.
        
        Validates: Requirements 2.1, 4.3
        """
        data = request.get_json()
        
        # Check mock sessions first
        if session_id in _mock_sessions:
            _mock_sessions[session_id]['current_location'] = {
                'latitude': data.get('latitude'),
                'longitude': data.get('longitude')
            }
            return {
                'success': True,
                'message': 'Location updated successfully',
                'session': _mock_sessions[session_id],
                'is_mock': True
            }, 200
        
        # Try database session
        session = WalkingSession.query.get(session_id)
        if not session:
            api.abort(404, 'Session not found')
        
        # Parse location
        try:
            location = Location(**data)
        except Exception as e:
            api.abort(400, f'Invalid location data: {str(e)}')
        
        try:
            from app.services.session_service import SessionService
            session_service = SessionService()
            session_service.update_session_location(session_id, location)
            session = WalkingSession.query.get(session_id)
            
            return {
                'success': True,
                'message': 'Location updated successfully',
                'session': {
                    'id': session.id,
                    'current_location': {
                        'latitude': session.current_latitude,
                        'longitude': session.current_longitude
                    },
                    'total_distance': session.total_distance,
                    'status': session.status
                }
            }, 200
            
        except Exception as e:
            error_response = ErrorResponse.create(e, include_details=current_app.debug)
            return error_response, 500


@api.route('/<string:session_id>/end')
class EndSession(Resource):
    """End session endpoint."""
    
    def post(self, session_id):
        """End walking session.
        
        Validates: Requirements 1.7
        """
        # Check mock sessions first
        if session_id in _mock_sessions:
            _mock_sessions[session_id]['status'] = 'completed'
            _mock_sessions[session_id]['end_time'] = datetime.now().isoformat()
            return {
                'success': True,
                'message': 'Session ended successfully',
                'summary': _mock_sessions[session_id],
                'is_mock': True
            }, 200
        
        # Try database session
        session = WalkingSession.query.get(session_id)
        if not session:
            api.abort(404, 'Session not found')
        
        try:
            from app.services.session_service import SessionService
            session_service = SessionService()
            summary = session_service.end_session(session_id)
            
            return {
                'success': True,
                'message': 'Session ended successfully',
                'summary': summary
            }, 200
            
        except Exception as e:
            error_response = ErrorResponse.create(e, include_details=current_app.debug)
            return error_response, 500


@api.route('/<string:session_id>/status')
class SessionStatus(Resource):
    """Session status endpoint."""
    
    def get(self, session_id):
        """Get session status.
        
        Validates: Requirements 1.5, 1.7, 2.1
        """
        # Check mock sessions first
        if session_id in _mock_sessions:
            return {
                'session': _mock_sessions[session_id],
                'is_mock': True
            }, 200
        
        # Try database session
        session = WalkingSession.query.get(session_id)
        if not session:
            api.abort(404, 'Session not found')
        
        return {
            'session': {
                'id': session.id,
                'user_id': session.user_id,
                'route_id': session.route_id,
                'status': session.status,
                'start_time': session.start_time.isoformat() if session.start_time else None,
                'end_time': session.end_time.isoformat() if session.end_time else None,
                'current_location': {
                    'latitude': session.current_latitude,
                    'longitude': session.current_longitude
                } if session.current_latitude and session.current_longitude else None,
                'visited_poi_ids': session.visited_poi_ids,
                'generated_music_ids': session.generated_music_ids,
                'route_history': session.route_history,
                'total_distance': session.total_distance
            }
        }, 200


@api.route('/history')
class SessionHistory(Resource):
    """Session history endpoint."""
    
    def get(self):
        """Get user's session history.
        
        Validates: Requirements 1.7
        """
        # Return mock sessions that are completed
        mock_completed = [s for s in _mock_sessions.values() if s.get('status') == 'completed']
        
        # Try to get database sessions too
        try:
            sessions = WalkingSession.query.filter_by(
                status='completed'
            ).order_by(WalkingSession.start_time.desc()).all()
        except Exception:
            sessions = []
        
        session_list = []
        for session in sessions:
            # Calculate duration
            duration_minutes = 0
            if session.start_time and session.end_time:
                duration = session.end_time - session.start_time
                duration_minutes = int(duration.total_seconds() / 60)
            
            # Get route info if available
            route_info = None
            if session.route:
                route_info = {
                    'distance_meters': session.route.distance_meters,
                    'waypoints': session.route.waypoints
                }
            
            session_list.append({
                'id': session.id,
                'start_time': session.start_time.isoformat() if session.start_time else None,
                'end_time': session.end_time.isoformat() if session.end_time else None,
                'duration_minutes': duration_minutes,
                'total_distance': session.total_distance,
                'visited_poi_count': len(session.visited_poi_ids) if session.visited_poi_ids else 0,
                'visited_poi_ids': session.visited_poi_ids,
                'route': route_info,
                'route_history': session.route_history
            })
        
        # Combine database sessions with mock completed sessions
        all_sessions = session_list + mock_completed
        
        # If no sessions, return mock history
        if not all_sessions:
            return {
                'sessions': MOCK_SESSION_HISTORY,
                'total_count': len(MOCK_SESSION_HISTORY),
                'is_mock': True
            }, 200
        
        return {
            'sessions': all_sessions,
            'total_count': len(all_sessions)
        }, 200
